#region File information

/**
 * File: GameObject.cs
 * Date: 08-03-2008
 * Auth: Jan-Jaap Severs
 * 
 * Desc: Every entity in the game that has some physical location in the gameworld is a GameObject.
 */

#endregion

#region Using statements

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

#endregion

namespace Gremlin.Game
{
    /// <summary>
    /// Every entity in the game that has some physical location in the gameworld is a GameObject.
    /// </summary>
    public abstract class GameObject
    {
        #region Member variables

        // The GameObject's position in the gameworld.
        protected Vector3 _position;

        // The GameObject's rotation.
        protected Quaternion _rotation;

        // The GameObject's scale.
        protected Vector3 _scale;

        // The GameObject's current rotation matrix (cached)
        protected Matrix _rotationMatrix;

        // The GameObject's current world matrix.
        protected Matrix _world;

        // Because a GameObject is not a GameComponent, we have to manually keep a reference to the Game instance.
        protected Microsoft.Xna.Framework.Game _game;

        // A boundingsphere for this object.
        protected BoundingSphere _boundingSphere;

        #endregion

        /// <summary>
        /// 
        /// </summary>
        protected GameObject(Microsoft.Xna.Framework.Game game)
        {
            _game = game;
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual void Initialize()
        {
            _position = Vector3.Zero;
            _rotation = Quaternion.Identity;
            _scale = Vector3.One;
            _world = Matrix.Identity;
            _rotationMatrix = Matrix.Identity;
            _boundingSphere = new BoundingSphere();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="gameTime"></param>
        public virtual void Update(GameTime gameTime)
        {
            Matrix matTrans = Matrix.CreateTranslation(_position);
            _rotationMatrix = Matrix.CreateFromQuaternion(_rotation);
            Matrix matScale = Matrix.CreateScale(_scale);

            _world = matScale * _rotationMatrix * matTrans;

            _boundingSphere.Center = _position;
        }

        /// <summary>
        /// Checks if this GameObject is inside the viewing frustum of a camera.
        /// </summary>
        /// <param name="frustum">The camera's frustum.</param>
        /// <returns>True if the GameObject is inside the frustum.</returns>
        public virtual bool IsInFrustum(BoundingFrustum frustum)
        {
            ContainmentType ct = frustum.Contains(_boundingSphere);
            if (ct == ContainmentType.Contains || ct == ContainmentType.Intersects)
                return true;

            return false;
        }

        /// <summary>
        /// Checks if this GameObject collides with another.
        /// </summary>
        /// <param name="other">The other GameObject to check.</param>        
        /// <returns>True if the two objects collide.</returns>
        public virtual bool Hits(GameObject other)
        {
            return _boundingSphere.Intersects(other.BoundingSphere);
        }

        public virtual void Move(Vector3 translation)
        {
            _position += translation;
        }

        public virtual void Rotate(Quaternion rotation)
        {
            _rotation *= rotation;
        }

        #region Accessors & actuators

        public virtual Vector3 Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public virtual Quaternion Rotation
        {
            get { return _rotation; }
            set { _rotation = value; }
        }

        public virtual Vector3 Scale
        {
            get { return _scale; }
            set { _scale = value; }
        }

        public virtual Vector3 Direction
        {
            get
            {
                Vector3 v = Vector3.TransformNormal(Vector3.Forward, _rotationMatrix);
                v.Normalize();
                return v;
            }
        }

        public virtual Vector3 Up
        {
            get
            {
                Vector3 v = Vector3.TransformNormal(Vector3.Up, _rotationMatrix);
                v.Normalize();
                return v;
            }
        }

        public virtual Matrix World
        {
            get { return _world; }
        }

        public virtual BoundingSphere BoundingSphere
        {
            get { return _boundingSphere; }
        }

        #endregion
    }
}
